package com;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;

import com.formatos.Formato;
import com.manager.FormatoFactory;
import com.manager.PoolDataSource;
import com.util.Util;

import exceptions.FiltroSinDatosException;
import exceptions.InvalidArgumentException;
import exceptions.ReporteSizeException;

public abstract class Reporte implements Cloneable {

	private String rutaReporte = null;

	private Map<String, Object> parametrosJasper = null;

	private Formato formatoReporte = null;
	
	private Long tamanoMaxReporte;
	
	public void setRutaReporte(String rutaReporte) {
		this.rutaReporte = Reporte.class.getResource("/").getPath() + rutaReporte;
	}

	public abstract void VerificarParametros(HttpServletRequest request)throws InvalidArgumentException;

	protected abstract JRDataSource executeQuery(Connection connection)throws SQLException;

	public abstract Object clone() throws CloneNotSupportedException;

	protected void copyAttributesTo(Reporte reporte) throws CloneNotSupportedException {
		reporte.rutaReporte = rutaReporte;
		reporte.parametrosJasper = new HashMap<String, Object>();
	}

	private JasperPrint getJasperPrint(Connection connection)
			throws JRException, SQLException {
		JRDataSource jRDataSource = executeQuery(connection);
		return JasperFillManager.fillReport(rutaReporte, parametrosJasper,jRDataSource);
	}

	public void generarReporte(HttpServletResponse response)
			throws JRException, IOException, SQLException, InvalidArgumentException, FiltroSinDatosException, ReporteSizeException {
		Connection connection = PoolDataSource.getInstance().getConection(PoolDataSource.CEREUS);
		File fileReporte = null;
		try {
			JasperPrint jasperPrint = getJasperPrint(connection);
			if (jasperPrint.getPages().isEmpty())
				throw new FiltroSinDatosException("El Reporte Solicitado no Posee Paginas para Mostrar");
			fileReporte = formatoReporte.escribirReporte(jasperPrint, response);
			long lengthReporte = fileReporte.length();
			connection.close();
			if (tamanoMaxReporte > 0 && lengthReporte >= tamanoMaxReporte ){
				fileReporte.delete();
				throw new ReporteSizeException("El tamaño del Reporte Generado es mayor al Máximo tamaño soportado por el Cliente: " + lengthReporte +" >= " + tamanoMaxReporte + " bytes");
			}
			com.formatos.Util.writeToOutputStream(response.getOutputStream(), fileReporte);
			fileReporte.delete();
		} catch (SQLException e) {
			if (fileReporte!=null)
				fileReporte.delete();
			connection.close();
			throw e;
		}catch (JRException e) {
			if (fileReporte!=null)
				fileReporte.delete();
			connection.close();
			throw e;
		}catch (IOException e) {
			if (fileReporte!=null)
				fileReporte.delete();
			connection.close();
			throw e;
		}catch (FiltroSinDatosException e) {
			if (fileReporte!=null)
				fileReporte.delete();
			connection.close();
			throw e;
		}catch (ReporteSizeException e) {
			if (fileReporte!=null)
				fileReporte.delete();
			connection.close();
			throw e;
		}
	}

	public void setFormato(String idFormato)
			throws CloneNotSupportedException, InvalidArgumentException {
		formatoReporte = FormatoFactory.getInstance().getFormato(idFormato);
	}

	protected void setParametrosJasper(String llave, Object valor) {
		this.parametrosJasper.put(llave, valor);
	}
	
	public void setTamanoMaxReporte(String maxSizeReporteCliente) throws InvalidArgumentException{
		Long tamanoMaxReporte_ = Util.toLong(maxSizeReporteCliente);
		tamanoMaxReporte = tamanoMaxReporte_== null ? -1 : tamanoMaxReporte_;
	}
}
